/* $RCSFile: SettingsTable.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Core/Configuration/Settings/SettingsTable.cs $
 * $log$
 * Revision 19 2011/02/22 01:23:08  christian.surieux
 *   V4 Migration 22/2/11
 * Revision 19 2011/02/22 01:22:11  christian.surieux
 *   V4 Migration 22/2/11
 * Revision 6 2010/08/06 19:56:27  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.IO;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Globalization;

using AddonNice.Core;
using AddonNice.UI;
using AddonNice.UI.WebControls;
using AddonNice.UI.DataTypes;
using AddonNice.Helpers;
using AddonNice.Security;
using AddonNice.Diagnostics;
using AddonNice.Settings;
using Telerik.Web.UI;

using Trace2=   System.Diagnostics.Trace;

namespace AddonNice.Configuration
{

	#region enum to define setting table type
	
	public enum SettingsTableType { Portal,Site,Page,Module,NewPage,Custom };

	#endregion enum to define setting table type
	
	#region Event argument class

	/// <summary>
	/// Class that defines data for the SettingsTable event
	/// </summary>
	public class SettingsTableEventArgs : EventArgs
	{
		public SettingsTable CurrentTable;
		public SettingsTableEventArgs(SettingsTable tb)
		{
			CurrentTable = tb;
		}
	}

	/// <summary>
	/// Class that defines data for the SettingsTableItem event
	/// </summary>
	public class SettingsTableItemEventArgs : EventArgs
	{
		public SettingsTableItemEventArgs(SettingItem item,SettingsTableType tp)
		{
			_currentItem    =   item;
			_SettingType    =   tp;
		}

		private SettingItem _currentItem;

		/// <summary>
		/// CurrentItem
		/// </summary>
		public SettingItem CurrentItem
		{
			get
			{
				return _currentItem;
			}
			set
			{
				_currentItem = value;
			}
		}

		SettingsTableType _SettingType  =   SettingsTableType.Module;
		public SettingsTableType SettingType
		{
			get
			{
				return _SettingType;
			}
		}
	}
	/// <summary>
	/// Send when bubbling events from SettingTable
	/// </summary>
	public class SettingsTableItemCommandEventArgs : CommandEventArgs
	{
		// private member variables
		private SettingItem  _item;
		private object _commandSource;

		#region Constructors
		/// <summary>
		/// Creates a new SettingsTableItemCommandEventArgs instance.
		/// </summary>
		/// <param name="item">The SettingsTableItem that contained the button that was clicked.</param>
		/// <param name="commandSource">The reference to the button that was clicked.</param>
		/// <param name="cea">The CommandEventArgs instance passed through the button's Command event.</param>
		public SettingsTableItemCommandEventArgs(SettingItem item, object commandSource, CommandEventArgs cea) : base(cea)
		{
			_item = item;
			_commandSource = commandSource;	
		}
		#endregion

		#region Properties
		/// <summary>
		/// Returns a reference to the RssFeedItem that contains the button that was clicked.
		/// </summary>
		public SettingItem Item
		{
			get
			{
				return _item;
			}			
		}

		/// <summary>
		/// Returns a reference to the Button/LinkButton Web control that was clicked.
		/// </summary>
		public object CommandSource
		{
			get
			{
				return _commandSource;
			}
		}
		#endregion
	}

	#endregion

	#region Delegate
	/// <summary>
	/// UpdateControlEventHandler delegate
	/// </summary>
	public delegate void UpdateControlEventHandler(object sender, SettingsTableItemEventArgs e);
	public delegate void SettingsTableEventHandler(object sender, SettingsTableEventArgs e);
	public delegate void SettingsTableItemEventHandler(object sender, SettingsTableItemEventArgs e);
	public delegate void SettingsTableItemCommandEventHandler(object sender, SettingsTableItemCommandEventArgs e);
	#endregion

	#region SettingsTable control

	#region TraceSwitch for all Settingstable related func
	public class SettingsTableTrace : ADNTraceSwitch
	{
		static public ADNTraceSwitch Sw = new ADNTraceSwitch("SettingsTableTrace", "Trace Switch for Settingstable");
	}
	#endregion TraceSwitch for all Settingstable related func

	/// <summary>
	/// Used to edit all settings: portals, pages and modules
	/// A databound control that takes in custom settings list in a SortedList<int,string>
	/// object and creates the hierarchy of the settings controls in two different ways. 
	/// The grouped settings are displayed in selectable tabs.  
	/// </summary>
	public class SettingsTable : WebControl, INamingContainer
	{
		const string strCtrlCount        =  "CtrlCount";
		
		#region Member variables

		private Hashtable _editControls;

		/// <summary>
		/// Used to store reference to base object it can be ModuleID or Portal ID
		/// </summary>
		public int ObjectID = -1;

		#endregion

		#region properties: visual and internal


		SettingsTableType _TableType    =   SettingsTableType.Module;
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("Module"),
		Description("Kind of settings managed by this table, determine the default datasource.")]
		public SettingsTableType TableType
		{
			get
			{
				return _TableType;
			}
			set
			{
				_TableType = value;
			}
		}

		bool _UseFieldSet    =   true;
		
		/// <summary>
		/// Should the PageView use fieldset html tag to enclose content.
		/// Default: true
		/// </summary>
		/// <param name="?"></param>
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("true"),
		Description("Should the PageView use fieldset html tag to enclose content.")]
		public bool UseFieldSet
		{
			get
			{
				return _UseFieldSet;
			}
			set
			{
				_UseFieldSet = value;
			}
		}

		bool _UseLegend    =   true;
		/// <summary>
		/// Should the PageView use legend html tag to encloise content.
		/// Default: true
		/// </summary>
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("true"),
		Description("Should the PageView use legend html tag to enclose content.")]
		public bool UseLegend
		{
			get
			{
				return _UseLegend;
			}
			set
			{
				_UseLegend = value;
			}
		}

		
		TabStripAlign  _Align   =   TabStripAlign.Left;
		
		/// <summary>
		/// Allows to transfer to RadTabStrip this parameter: center, justify, left, right
		/// Default left
		/// </summary>
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("TabStripAlign.Left"),
		Description("Allows to transfer to RadTabStrip this parameter: center, justify, left, right.")]
		public TabStripAlign Align
		{
			get
			{
				return _Align;
			}
			set
			{
				_Align  = value;
			}
		}

		TabStripOrientation _Orientation =   TabStripOrientation.HorizontalTop;
		/// <summary>
		/// Allows to transfer to RadTabStrip this parameter: HorizontalTop, HorizontalBottom,VerticalLeft,VerticalRight
		/// Default HorizontalTop
		/// </summary>
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("TabStripOrientation.HorizontalTop"),
		Description(" Allows to transfer to RadTabStrip this parameter: HorizontalTop, HorizontalBottom,VerticalLeft,VerticalRight.")]
		public TabStripOrientation Orientation 
		{
			get
			{
				return _Orientation;
			}
			set
			{
				_Orientation  = value;
			}
		}
		
		int _GCellPadding        =   0;
		
		/// <summary>
		/// CellPading for the inner table which contains tabstrip and Multipage in its cells
		/// </summary>
		public int GCellPadding
		{
			get
			{
				return _GCellPadding;
			}
			set
			{
				_GCellPadding = value;
			}
		}

		int _GCellSpacing        =   0;
		
		/// <summary>
		/// CellSpacing for the inner table which contains tabstrip and Multipage in its cells
		/// </summary>
		public int GCellSpacing
		{
			get
			{
				return _GCellSpacing;
			}
			set
			{
				_GCellSpacing = value;
			}
		}

		int _VSeparator        =   2;
		
		/// <summary>
		/// VSeparator set a width in px to separate the left tabstrip from the right multipage
		/// </summary>
		public int VSeparator
		{
			get
			{
				return _VSeparator;
			}
			set
			{
				_VSeparator = value;
			}
		}

		int _CellPadding        =   0;
		
		/// <summary>
		/// CellPading for each PageView contained Table use with care
		/// </summary>
		public int CellPadding
		{
			get
			{
				return _CellPadding;
			}
			set
			{
				_CellPadding = value;
			}
		}

		int _CellSpacing        =   0;
		
		/// <summary>
		/// CellSpacing for each PageView contained Table,use with care
		/// </summary>
		public int CellSpacing
		{
			get
			{
				return _CellSpacing;
			}
			set
			{
				_CellSpacing = value;
			}
		}

		bool _UseGenPanel   = false;
		
		/// <summary>
		/// Force usage of a Panel to enclose the table of setting when set true
		/// else a div is used
		/// Default: False
		/// </summary>
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("false"),
		Description("Force usage of an .Net Panel to contain all controls when set true.")]
		public bool UseGenPanel
		{

			get
			{
				return _UseGenPanel;
			}
			set
			{
				_UseGenPanel  = value;
			}
		}

		public override Page Page
		{
			get
			{
				return base.Page;
			}
			set
			{
				base.Page       =   value;
				// must reset local
				_SettingsParentPage   =   null;
			}
		}

		ADNPage _SettingsParentPage   = null;
		private ADNPage SettingsParentPage
		{
			get
			{
				if (_SettingsParentPage == null)
				{
					if ( Page is ADNPage )
						_SettingsParentPage = (ADNPage)Page;
				}
				return _SettingsParentPage;
			}
		}

		bool _UseToolTips   = true;
		List<Control> TarGetToolTips    =   new List<Control>();
		
		/// <summary>
		/// When true and a ToolTipManager is found on the page, insert the help image in the tooltip collection
		/// Default: True
		/// </summary>
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("true"),
		Description("When true, all settings item that require a postback are entered in the RadAjaxManer with tehre dependency to do Asynch postBack.")]
		public bool UseToolTips
		{

			get
			{
				return _UseToolTips;
			}
			set
			{
				_UseToolTips  = value;
			}
		}

		bool _UseAjax   = true;
		
		/// <summary>
		/// When true, all settings item that require a postback are entered in the RadAjaxManer with their dependency to do Asynch postBack
		/// Default: True
		/// </summary>
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("true"),
		Description("When true, all settings item that require a postback are entered in the RadAjaxManer with tehre dependency to do Asynch postBack.")]
		public bool UseAjax
		{

			get
			{
				return _UseAjax;
			}
			set
			{
				_UseAjax  = value;
			}
		}

		bool _CausesValidation   = false;
		
		/// <summary>
		/// Should the tabStrip posting cause validation
		/// Default: False
		/// </summary>
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("false"),
		Description("Should the tabStrip posting cause validation.")]
		public bool CausesValidation
		{
			get
			{
				return _CausesValidation;
			}
			set
			{
				_CausesValidation  = value;
			}
		}

		/// <summary>
		/// The width for the multipage
		/// </summary>
		Unit _MPWidth  =   Unit.Empty;
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("Unit.Empty"),
		Description("The width for the multipage.")]
		public Unit MPWidth
		{
			get
			{
				if ( _MPWidth == Unit.Empty )
				{
					if ( IsVertical )
							_MPWidth    =   Config.SettingsGroupingVertWidth;
					else    _MPWidth    =   Config.SettingsGroupingWidth;
				}
				return _MPWidth;
			}
			set
			{
				_MPWidth = value;
			}
		}

		/// <summary>
		/// The height for the multipage
		/// </summary>
		Unit _MPHeight  =    Unit.Empty;
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("Unit.Empty"),
		Description("The height for the multipage.")]
		public Unit MPHeight
		{
			get
			{
				if ( _MPHeight == Unit.Empty )
				{
					if ( IsVertical )
							_MPHeight   =   Config.SettingsGroupingVertHeight;
					else    _MPHeight   =   Config.SettingsGroupingHeight;
				}
				return _MPHeight;
			}
			set
			{
				_MPHeight = value;
			}
		}

		/// <summary>
		/// The width for the tabstrip
		/// </summary>
		Unit _TabWidth  =   Unit.Empty;
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("Unit.Empty"),
		Description("The tabstrip width.")]
		public Unit TabWidth
		{
			get
			{
				if ( _TabWidth == Unit.Empty )
				{
					if ( IsVertical )
							_TabWidth   =   Config.SettingsGroupingTabVertWidth;
					else    _TabWidth   =   Config.SettingsGroupingTabWidth;
				}
				return _TabWidth;
			}
			set
			{
				_TabWidth = value;
			}
		}

		/// <summary>
		/// The height for the tabstrip
		/// </summary>
		Unit _TabHeight  =    Unit.Empty;
		[Bindable(true),
		Category("Behavior"),
		DefaultValue("Unit.Empty"),
		Description("The height for the tabstrip.")]
		public Unit TabHeight
		{
			get
			{
				if ( _TabHeight == Unit.Empty )
				{
					if ( IsVertical )
							_TabHeight  =   Config.SettingsGroupingTabVertHeight;
					else    _TabHeight  =   Config.SettingsGroupingTabHeight;
				}
				return _TabHeight;
			}
			set
			{
				_TabHeight  = value;
			}
		}

		/// <summary>
		/// TabStrip is vertical ? set according Orientation parameter
		/// </summary>
		[Browsable(false)]
		public bool IsVertical
		{
			get
			{
				return (Orientation == TabStripOrientation.VerticalLeft ||
							Orientation == TabStripOrientation.VerticalRight );
			}
		}

		[Browsable(false)]
		protected override HtmlTextWriterTag TagKey
		{
			get
			{
				// render the out tag as div
				return HtmlTextWriterTag.Div;
			}
		}

		SettingsDictionary _DataSource  =   null;

		/// <summary>
		/// DataSource, it is limited to SortedList type
		/// </summary>
		[Browsable(false)]
		public SettingsDictionary DataSource
		{
			get
			{
				if ( SettingsTableTrace.Sw.TraceVerbose )
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable DataSource Get TableType: {0}, is null: {1}",TableType,( _DataSource == null )),SettingsTableTrace.Sw.Info);
				if ( DesignMode )
					return null;
				if ( _DataSource == null )
				{
					try
					{
						PortalSettings ps           =   (PortalSettings)HttpContext.Current.Items[StStr.strPortalSettings];
						switch (TableType)
						{
							case SettingsTableType.Module:
								if (SettingsParentPage != null && SettingsParentPage is StdAuxPage)
									_DataSource     =   ((StdAuxPage)SettingsParentPage).moduleSettingsDic;
								break;
							case SettingsTableType.Page:
								if (SettingsParentPage != null)
									_DataSource     =   SettingsParentPage.Settings;
								break;
							case SettingsTableType.Site:
								_DataSource         =   ps.CustomSettings;
								break;
							case SettingsTableType.Portal:
								int currentPortalID =   -1;
								object ob = Page.Request.Params[StStr.PortalID];
								if (ob != null)
									currentPortalID =   int.Parse(ob.ToString());
								_DataSource         =   ps.CustomSettings;
								if (currentPortalID != -1 && currentPortalID != ps.PortalID )
								{
									// Obtain PortalSettings of this Portal
									PortalSettings currentPortalSettings = new PortalSettings(currentPortalID);
									//_DataSource = PortalSettings.GetPortalCustomSettings(currentPortalSettings.PortalID, (PortalSettingsDictionary)DataSource);
									_DataSource     =   currentPortalSettings.CustomSettings;
								}
								break;
							case SettingsTableType.NewPage:
								if (SettingsParentPage != null)
								{
									_DataSource     =   SettingsParentPage.portalSettings.ActivePageSettings.GetDupPageCustomSettings();
								}
								break;
							 case SettingsTableType.Custom:
								break;
						}
					}
					catch (Exception ex)
					{
						if (  SettingsTableTrace.Sw.TraceError )
							Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SettingsTable DataSource Get ex: {0}",ex),SettingsTableTrace.Sw.Info);
						throw;
					}
					if (  SettingsTableTrace.Sw.TraceVerbose )
						Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable DataSource Get NeedDataSource != null: {0}",( NeedDataSource != null ) ),SettingsTableTrace.Sw.Info);
					if ( ( _DataSource == null ) && ( NeedDataSource != null ) )
					{
						SettingsTableEventArgs ev   =   new SettingsTableEventArgs(this);
						NeedDataSource(this,ev);
					}
					if (  _DataSource != null && SettingsTableTrace.Sw.TraceVerbose )
						Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable DataSource Get TableType: {0}, Count: {1}",TableType,_DataSource.Count ),SettingsTableTrace.Sw.Info);
				}
			return _DataSource;
			}
			
			set
			{
				if ( SettingsTableTrace.Sw.TraceVerbose )
				{
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable DataSource Set IsNull: {0}", value == null),SettingsTableTrace.Sw.Info);
					if ( value != null )
						Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable DataSource Set Count: {0}", value.Count),SettingsTableTrace.Sw.Info);
				}
				_DataSource = value;
			}
		}

		/// <summary>
		/// Settings control collection, it is initialized only  when referenced.
		/// </summary>
		[Browsable(false)]
		protected Hashtable EditControls
		{
			get
			{
				if (_editControls == null)
					_editControls = new Hashtable();
				return _editControls;
			}
		}

		#endregion

		#region Events

		public event SettingsTableEventHandler NeedDataSource;

		public event UpdateControlEventHandler UpdateControl;
		/// <summary>
		/// Occurs when an SettingsTableItem is created.
		/// </summary>
		public event SettingsTableItemEventHandler ItemCreated;

		/// <summary>
		/// Occurs after an SettingsTableItem is databound.
		/// </summary>
		public event SettingsTableItemEventHandler ItemDataBound;

		/// <summary>
		/// Occurs when a button in an SettingsTableItem is clicked.
		/// </summary>
		public event SettingsTableItemCommandEventHandler ItemCommand;

		#endregion

		#region Events processing

		/// <summary>
		/// This method provides a way to trigger UpdateControl event
		/// for the child controls of this control from outside.
		/// </summary>
		public void UpdateControls()
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable UpdateControls BEG Keys.Count: {0}", EditControls.Keys.Count),SettingsTableTrace.Sw.Info);
			try
			{
				foreach (string key in EditControls.Keys)
				{
					if ( string.IsNullOrEmpty(key))
						continue;
					Control c                   =   (Control)EditControls[key];
					// Dependents items will be saved by their ownera
					if (!string.IsNullOrEmpty(c.ID) && DataSource.ContainsKey(c.ID))
					{
					   SettingItem currentItem  =   _DataSource[c.ID];
						if (SettingsTableTrace.Sw.TraceVerbose)
							Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable UpdateControls ReadData key: {0}, currentItem.EnglishName: {1}, StatusOk: {2}, isDependant: {3}.", 
								new object[]{key, currentItem.EnglishName,currentItem.StatusOk,currentItem.isDependant }), SettingsTableTrace.Sw.Info);
						if ( !currentItem.StatusOk || currentItem.isDependant )
							continue;
						currentItem.ReadData(c);
						if (SettingsTableTrace.Sw.TraceVerbose)
							Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable UpdateControls key: {0}, currentItem.EnglishName: {1}, currentItem.Value: {2}", key, currentItem.EnglishName, currentItem.Value), SettingsTableTrace.Sw.Info);
						OnUpdateControl(new SettingsTableItemEventArgs(currentItem,TableType));
					}
					else
					{
						if (SettingsTableTrace.Sw.TraceError)
							Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SettingsTable UpdateControls key='{0}' no Setting.", key), SettingsTableTrace.Sw.Info);
					}
				}
			}
			catch (Exception ex)
			{
				if ( SettingsTableTrace.Sw.TraceError )
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SettingsTable UpdateControls ex: {0}", ex),SettingsTableTrace.Sw.Info);
				throw;
			}
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable UpdateControls END.",SettingsTableTrace.Sw.Info);
		}
		/// <summary>
		/// Raises UpdateControl Event 
		/// </summary>
		protected virtual void OnUpdateControl(SettingsTableItemEventArgs e)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnUpdateControl CurrentItem: {0}",e.CurrentItem.EnglishName),SettingsTableTrace.Sw.Info);
			if (UpdateControl != null)
			{
				UpdateControl(this, e);
			}
		}

		/// <summary>
		/// Raises the ItemCreated event.  This allows you to provide a custom handler for the event.
		/// </summary>
		protected virtual void OnItemCreated(SettingsTableItemEventArgs e)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnItemCreated CurrentItem: {0}",e.CurrentItem.EnglishName),SettingsTableTrace.Sw.Info);
			if (ItemCreated != null)
				ItemCreated(this, e);
		}

		/// <summary>
		/// Raises the ItemDataBound event.  This allows you to provide a custom handler for the event.
		/// </summary>
		protected virtual void OnItemDataBound(SettingsTableItemEventArgs e)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnItemDataBound CurrentItem: {0}",e.CurrentItem.EnglishName),SettingsTableTrace.Sw.Info);
			if (ItemDataBound != null)
				ItemDataBound(this, e);
		}

		/// <summary>
		/// Raises the ItemCommand event.  This allows you to provide a custom handler for the event.
		/// </summary>
		protected virtual void OnItemCommand(SettingsTableItemCommandEventArgs e)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnItemCommand Item: {0}",e.Item.EnglishName),SettingsTableTrace.Sw.Info);
			if (ItemCommand != null)
				ItemCommand(this, e);
		}

		#region Event Bubbling Methods

		protected override bool OnBubbleEvent(object source, EventArgs args)
		{
			bool isSettingCmd   =   args is SettingsTableItemCommandEventArgs;
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnBubbleEvent BEG isSettingCmd: {0}",isSettingCmd),SettingsTableTrace.Sw.Info);
			// only bother bubbling appropriate events
			if ( isSettingCmd )
			{
				OnItemCommand((SettingsTableItemCommandEventArgs) args);
				if ( SettingsTableTrace.Sw.TraceVerbose )
					Trace2.WriteLine("[V]SettingsTable OnBubbleEvent END True.",SettingsTableTrace.Sw.Info);
				return true;
			}
			return false;
		}
		
		#endregion
		
		#endregion

		#region overriden methods

		protected override void CreateChildControls()
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateChildControls BEG ChildControlsCreated: {0}",ChildControlsCreated),SettingsTableTrace.Sw.Info);
			if ( !ChildControlsCreated )
			{
				int? ob = (int?)ViewState[strCtrlCount];
				if (SettingsTableTrace.Sw.TraceVerbose)
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateChildControls CtrlCount defined: {0}", ob.HasValue), SettingsTableTrace.Sw.Info);
				CreateControlHierarchy(!ob.HasValue);
			}
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable CreateChildControls END.",SettingsTableTrace.Sw.Info);
		}

		protected override void LoadViewState(object savedState)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable LoadViewState BEG savedState: {0}",savedState),SettingsTableTrace.Sw.Info);
			base.LoadViewState(savedState);
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable LoadViewState END.",SettingsTableTrace.Sw.Info);
		}

		protected override object SaveViewState()
		{
			if (SettingsTableTrace.Sw.TraceVerbose)
			{
				Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]SettingsTable SaveViewState BEG ID: {0}, ViewState.Count: {1}", ID, ViewState.Count), SettingsTableTrace.Sw.Info);
				foreach (string key in ViewState.Keys )
					Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]SettingsTable SaveViewState key: '{0}', value: '{1}'", key, ViewState[key]), SettingsTableTrace.Sw.Info);
			}            
			object ob   = base.SaveViewState();
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable SaveViewState END.",SettingsTableTrace.Sw.Info);
			return ob;
		}

		protected override void TrackViewState()
		{
			if (SettingsTableTrace.Sw.TraceVerbose)
				Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]SettingsTable TrackViewState BEG IsTrackingViewState: {0}.", IsTrackingViewState), SettingsTableTrace.Sw.Info);
			base.TrackViewState();
			if (SettingsTableTrace.Sw.TraceVerbose)
				Trace2.WriteLine("[V]SettingsTable TrackViewState END.", SettingsTableTrace.Sw.Info);
		}

#if DEBUG
		protected override void Render(HtmlTextWriter writer)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable Render BEG.",SettingsTableTrace.Sw.Info);
			base.Render(writer);
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable Render END.",SettingsTableTrace.Sw.Info);
		}

		protected override void OnPreRender(EventArgs e)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable OnPreRender BEG.",SettingsTableTrace.Sw.Info);
			base.OnPreRender(e);
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable OnPreRender END.",SettingsTableTrace.Sw.Info);
		}

#endif

		/// <summary>
		/// Take care to set all controls to null to avoid their storage in cache which could block the garbage collector
		/// </summary>
		protected override void OnUnload(EventArgs e)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnUnload BEG  _DataSource null: {0}", _DataSource == null ),SettingsTableTrace.Sw.Info);
			if ( _DataSource == null || !ChildControlsCreated )
				return;
			foreach (string key in _DataSource.Keys)
			{
				SettingItem wsetting    =   _DataSource[key];
				if (wsetting.InnerControl != null)
				{
					if (wsetting.Required && wsetting.Ok4Validators)
					{
						string ID       =   wsetting.InnerControl.ID + "_req_validator";
						Control req     =   FindControl(ID);
						if ((req != null) && (req is RequiredFieldValidator))
						{
							if ( SettingsTableTrace.Sw.TraceVerbose )
								Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnUnload validator found: {0}",ID),SettingsTableTrace.Sw.Info);
							((RequiredFieldValidator)req).ControlToValidate = string.Empty;
							((RequiredFieldValidator)req).Enabled = false;
						}
					}
					wsetting.ResetControl();
				}
			}
			base.OnUnload(e);
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable OnUnload END.",SettingsTableTrace.Sw.Info);
		}
		
		protected override void OnLoad(EventArgs e)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnLoad BEG IsPostBack: {0}",Page.IsPostBack),SettingsTableTrace.Sw.Info);
			base.OnLoad(e);
			if ( SettingsParentPage != null )
			{
				if ( UseAjax )
					foreach (string currentSetting in OrderedSettings.Values)
					{
						SettingItem currentItem =   DataSource[currentSetting];
						if ( currentItem.HandleChanges)
						{
							Control ctl             =   currentItem.EditControl;
							SettingsParentPage.AddAjaxSetting(ctl, ctl);
							foreach (SettingItem s in currentItem.DependentItems)
							{
								if (SettingsTableTrace.Sw.TraceVerbose)
									Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnLoad AddAjaxSetting to: {0} for: {1}.", 
										currentSetting, s.EnglishName), SettingsTableTrace.Sw.Info);
								SettingsParentPage.AddAjaxSetting(ctl, s.EditControl);
							}
						}
					}
				// Tooltips 
				if ( !Page.IsPostBack && UseToolTips )
					foreach(Control ctl in TarGetToolTips)
						SettingsParentPage.AddToolTipTarget(ctl.ClientID,true,TootipPos.Top);
			}
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable OnLoad END.",SettingsTableTrace.Sw.Info);
		}

		protected override void OnInit(EventArgs e)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable OnInit BEG ChildControlsCreated: {0}.",ChildControlsCreated),SettingsTableTrace.Sw.Info);
			// Forces control creation here if not already done
			EnsureChildControls();
			base.OnInit(e);
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable OnInit END.",SettingsTableTrace.Sw.Info);
		}


#if DEBUG
		public override void DataBind()
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable DataBind BEG ID: {0}.",ID),SettingsTableTrace.Sw.Info);
			base.DataBind();
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable DataBind END.",SettingsTableTrace.Sw.Info);
		}
#endif

		protected override void DataBind(bool raiseOnDataBinding)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]SettingsTable DataBind 2 BEG raiseOnDataBinding: {0}, ChildControlsCreated: {1}, IsTrackingViewState: {2}.", 
					raiseOnDataBinding, ChildControlsCreated,IsTrackingViewState), SettingsTableTrace.Sw.Info);
			EnsureChildControls();
			bool dataSourceSet = (DataSource != null);

			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable DataBind dataSource Ok: {0}, ChildContolCreated: {1}.",dataSourceSet,ChildControlsCreated),SettingsTableTrace.Sw.Info);
			if (!dataSourceSet) // should rebind later
			{
				if (SettingsTableTrace.Sw.TraceVerbose)
					Trace2.WriteLine("[V]SettingsTable DataBind 2 END NO DataSource.", SettingsTableTrace.Sw.Info);
				return;
			}

			if (raiseOnDataBinding)
			{
				OnDataBinding(EventArgs.Empty);
			}

			/*
			if (SettingsTableTrace.Sw.TraceVerbose)
				Trace2.WriteLine("[V]SettingsTable DataBind 2 ClearChildViewState.", SettingsTableTrace.Sw.Info);
			// clear existing control hierarchy
			ClearChildViewState();
			// start tracking changes during databinding
			if (SettingsTableTrace.Sw.TraceVerbose)
				Trace2.WriteLine("[V]SettingsTable DataBind 2 start tracking ViewState changes.", SettingsTableTrace.Sw.Info);
			TrackViewState();
			*/
			// bind setting items values hierarchy from the data source
			BindChildControls();
			
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable DataBind 2 END.",SettingsTableTrace.Sw.Info);
		}
		
		#endregion

		#region Control Methods

#if DEBUG

		/// <summary>
		///  Just here to check any call, normally replaced by BindChildControls
		/// </summary>
		protected override void DataBindChildren()
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable DataBindChildren BEG ChildControlsCreated: {0}", ChildControlsCreated),SettingsTableTrace.Sw.Info);
			base.DataBindChildren();
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable DataBindChildren END.",SettingsTableTrace.Sw.Info);
		}
#endif
		/// <summary>
		/// Ensure that values from setting items are pushed in their associated controls
		/// </summary>
		protected void BindChildControls()
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable BindChildControls BEG ChildControlsCreated: {0}", ChildControlsCreated),SettingsTableTrace.Sw.Info);
			if ( DesignMode )
				return;
			if (!ChildControlsCreated)
			{
				const string msg1               =   "[E]SettingsTable BindChildControls ChildControls not created.";
				if ( SettingsTableTrace.Sw.TraceError )
					Trace2.WriteLine( msg1,SettingsTableTrace.Sw.Info);
				throw(new Exception(msg1));
			}
			try
			{
				foreach (string key in EditControls.Keys)
				{
					if ( string.IsNullOrEmpty(key))
						continue;
					Control c                   =   (Control)EditControls[key];
					if (!string.IsNullOrEmpty(c.ID) && DataSource.ContainsKey(c.ID))
					{
						SettingItem currentItem =   _DataSource[c.ID];
						if (SettingsTableTrace.Sw.TraceVerbose)
							Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable BindChildControls  before DataBind  key: {0}, currentItem.EnglishName: {1}, status: {2}.", 
								key, currentItem.EnglishName,currentItem.StatusOk), SettingsTableTrace.Sw.Info);
						// don't bind invalid status
						if ( !currentItem.StatusOk )
							continue;
						currentItem.DataBind();
						SettingsTableItemEventArgs e    =   new SettingsTableItemEventArgs(currentItem,TableType);
						OnItemDataBound(e);		// raise the ItemDataBound event
						if (SettingsTableTrace.Sw.TraceVerbose)
							Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable BindChildControls key: {0}, currentItem.EnglishName: {1}, after DataBind currentItem.Value: {2}", key, currentItem.EnglishName, currentItem.Value), SettingsTableTrace.Sw.Info);
					}
					else
					{
						string msg              =    string.Format("[E]SettingsTable BindChildControls key='{0}' no Setting.", key);
						if (SettingsTableTrace.Sw.TraceError)
							Trace2.WriteLine( msg, SettingsTableTrace.Sw.Info);
						throw( new Exception(msg));
					}
				}
			}
			catch (Exception ex)
			{
				if ( SettingsTableTrace.Sw.TraceError )
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SettingsTable BindChildControls ex: {0}", ex),SettingsTableTrace.Sw.Info);
				throw;
			}
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine("[V]SettingsTable BindChildControls END.",SettingsTableTrace.Sw.Info);
		}
		
		/// <summary>
		/// Creating control hierarchy of this control. 
		/// </summary>
		/// <param name="saveinViewState">
		/// If true saves the Ctl number in ViewState
		/// </param>
		protected virtual void CreateControlHierarchy(bool saveinViewState)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateControlHierarchy BEG saveinViewState: {0}", saveinViewState),SettingsTableTrace.Sw.Info);
			if ( DesignMode )
				return;
			// re-order settings items
			ClearChildViewState();
			Controls.Clear();
			CreateGroupingTabs(saveinViewState, OrderedSettings);
			ChildControlsCreated    = true;
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( "[V]SettingsTable CreateControlHierarchy END.",SettingsTableTrace.Sw.Info);
		}

		SortedList<int, string> _OrderedSettings    =   null;
		SortedList<int, string> OrderedSettings
		{
			get
			{
				if (_OrderedSettings == null)
					_OrderedSettings = ProcessDataSource();
				return _OrderedSettings;
			}
		}

		/// <summary>
		/// Re-order the settings items. The reason why this processing is
		/// necessary is that two settings items may have same order. 
		/// </summary>
		protected virtual SortedList<int, string> ProcessDataSource()
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable ProcessDataSource Settings null: {0}", _DataSource == null ),SettingsTableTrace.Sw.Info);
			// Force the list to obey SettingItem.Order property and divide it into groups
			// Settings with no order have a progressive order number 
			//         based on their position on list
			SortedList<int, string> SettingsOrder = new SortedList<int, string>();
			int order                   =   0;
			foreach (string key in DataSource.Keys)
			{
				SettingItem wsetting    =   _DataSource[key];
				if ( wsetting.Key != key )
				{
					string msg          =   string.Format("[E]SettingsTable ProcessDataSource Settings Settings[key].Key:{0} != key:{1}",wsetting.Key,key);
					if ( SettingsTableTrace.Sw.TraceError )
						Trace2.WriteLine( msg,SettingsTableTrace.Sw.Info);
					throw new ArgumentException(msg);
				}
				int group               =   100*(int)wsetting.Group;
				order                   =   group+wsetting.Order;
				while (SettingsOrder.ContainsKey(order))
				{
					// be sure do not have duplicate order key or 
					// we get an error
					order++;
				}
				SettingsOrder.Add(order, key);
			}
			return SettingsOrder;
		}

		#endregion

		#region private help functions

		/// <summary>
		/// Create the grouping tabs control hirarchy
		/// </summary>
		private void CreateGroupingTabs(bool saveinViewState, SortedList<int,string> SettingsOrder)
		{
			if ( SettingsOrder.Count == 0)
			{
				if ( SettingsTableTrace.Sw.TraceVerbose )
					Trace2.WriteLine( "[V]SettingsTable CreateGroupingTabs BEG SettingsOrder.Count == 0 exiting.",SettingsTableTrace.Sw.Info);
				return;
			}

			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateGroupingTabs BEG saveinViewState: {0}, UseAjax: {1}, Use Panel: {2}.",
					saveinViewState, UseAjax,UseGenPanel),SettingsTableTrace.Sw.Info);
			Control tabPanelGroup               =   null;
			Panel genPanel                      =   null;
			if ( UseGenPanel )
			{
				genPanel                        =   new Panel();
				tabPanelGroup                   =   genPanel;
			}
			else
			{
				tabPanelGroup                   =   new HtmlGenericControl(StStr.Div);
				((HtmlGenericControl)tabPanelGroup).Attributes.Add("class", "tabPanelGroup");
				((HtmlGenericControl)tabPanelGroup).Style.Add( HtmlTextWriterStyle.Display, "block");
			}
			//tabPanelGroup.ID                =   string.Format("{0}_tpg1",ClientID);
			tabPanelGroup.ID                =   "Stpg1";
			Control TabStripContainer       =   null;
			Control MultiPageContainer      =   null;
			
			Table tb0                       =   new Table();
			tb0.CellPadding                 =   GCellPadding;
			tb0.CellSpacing                 =   GCellSpacing;
			tb0.BorderWidth                 =   0;
			tb0.Width                       =   Width;
			//tb0.Height                      =   Height;
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateGroupingTabs Table Width: {0}, Height: {1}, IsVertical: {2}", Width,Height, IsVertical),SettingsTableTrace.Sw.Info);
			if ( !Height.IsEmpty && (Height.Value != 0 ))
				tb0.Height                  =   Height;
			//tb0.ID                          =   string.Format("{0}_TbVert",ClientID);
			tb0.ID                          =   "STbVert";
			TableRow rw                     =   new TableRow();
			// no width in tr ->rw.Width                        =   new Unit(100,UnitType.Percentage);
			TableCell cel                   =   new TableCell();
			// if Vertical we put the TabStrip and MultiPage in the same cell
			if ( IsVertical )
			{
				cel.Width                   =   (Width == Unit.Empty) ? new Unit(100,UnitType.Percentage):Width;
				cel.VerticalAlign           =   VerticalAlign.Top;
				rw.Cells.Add(cel);
				TabStripContainer           =   cel;
				MultiPageContainer          =   cel;
				tb0.Rows.Add(rw);
			}
			// When horiz we create 2 separate rows to put tabstrip on top of multipage
			else
			{
				cel.Width                   =   (Width == Unit.Empty) ? new Unit(100,UnitType.Percentage):Width;
				cel.VerticalAlign           =   VerticalAlign.Top;
				rw.Cells.Add(cel);
				TabStripContainer           =   cel;
				tb0.Rows.Add(rw);
				rw                          =   new TableRow();
				//rw.Width                    =   new Unit(100,UnitType.Percentage);
				cel                         =   new TableCell();
				cel.Width                   =   (Width == Unit.Empty) ? new Unit(100,UnitType.Percentage):Width;
				cel.VerticalAlign           =   VerticalAlign.Top;
				rw.Cells.Add(cel);
				MultiPageContainer          =   cel;
				tb0.Rows.Add(rw);
			}
			//  We create the TabStrip that will contain the dynamics tabs
			RadTabStrip tabStrip            =   new RadTabStrip();
			tabStrip.EnableViewState        =   false;
			tabStrip.ClientIDMode           =   System.Web.UI.ClientIDMode.Static;
			tabStrip.ID                     =   "SStrip";
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateGroupingTabs SkinID: {0}",string.IsNullOrEmpty(SkinID) ? string.Empty:SkinID),SettingsTableTrace.Sw.Info);
			// uses the control SkinID for its skin or the default RadTabStrip set by file RadTabStrip.skin in current theme
			if ( !string.IsNullOrEmpty(SkinID))
			{
				tabStrip.Skin               =   SkinID; 
				tabStrip.SkinID             =   SkinID; 
			}
			
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateGroupingTabs tabStrip TabWidth.Value: {0}",TabWidth.Value),SettingsTableTrace.Sw.Info);
			if ( !TabWidth.IsEmpty && (TabWidth.Value != 0) )
				tabStrip.Width              =   TabWidth;
			if ( IsVertical )
			{
				tabStrip.Style.Add("float", "left");
			}
			if ( TabHeight.Value != 0 )
				tabStrip.Height             =   TabHeight;
			tabStrip.SelectedIndex          =   0;
			tabStrip.AutoPostBack           =   false;
			tabStrip.CausesValidation       =   CausesValidation;
			tabStrip.Align                  =   Align;
			tabStrip.Orientation            =   Orientation;
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable createGroupingTabs RadTabStrip created Width: {0}, Heigth: {1}, Skin: {2}, Align: {3}, Orientation: {4}",
					new object[]{tabStrip.Width,tabStrip.Height,tabStrip.Skin,tabStrip.Align,tabStrip.Orientation}),SettingsTableTrace.Sw.Info);
			TabStripContainer.Controls.Add(tabStrip);
			if ( ( Orientation == TabStripOrientation.VerticalLeft ) && (VSeparator != 0) )
			{
				HtmlGenericControl dvsep    =   new HtmlGenericControl("div");
				dvsep.Style.Add(HtmlTextWriterStyle.Width,string.Format("{0}px",VSeparator));
				dvsep.Style.Add("float", "left");
			  //dvsep.ID                    =  string.Format("{0}_VSep",ClientID); 
				dvsep.ID                    =  "SVSep"; 
				dvsep.InnerHtml             =   "&nbsp;";
				dvsep.Attributes.Add("class","SettingTable_VSeparator");
				TabStripContainer.Controls.Add(dvsep);
			}

			// Now the related Multipage
			RadMultiPage RMP                =   new RadMultiPage();
			RMP.EnableViewState             =   false;
			//RMP.ID                          =   string.Format("{0}_RadMultiPage1",ClientID);
			RMP.ID                          =   "SMultiPage";
			RMP.ClientIDMode                =   System.Web.UI.ClientIDMode.Static;
			// we link them by the MP clienID (see telerik)
			tabStrip.MultiPageID            =   RMP.ClientID;
			// zero means dynamic for height and width
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateGroupingTabs RMP MPWidth.Value: {0}, MPHeight.Value: {1}",
					MPWidth.Value,MPHeight.Value),SettingsTableTrace.Sw.Info);
			if ( !MPWidth.IsEmpty && ( MPWidth.Value != 0 ))
				RMP.Width                   =   MPWidth;
			if ( !MPHeight.IsEmpty && (MPHeight.Value != 0 ))
				RMP.Height                  =   MPHeight;

			RMP.SelectedIndex               =   tabStrip.SelectedIndex;
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable createGroupingTabs RadMultipage created Width: {0}, Heigth: {1}", 
					RMP.Width,RMP.Height),SettingsTableTrace.Sw.Info);
			MultiPageContainer.Controls.Add(RMP);

			// Then we fill the Multipage with RadPageViews
			RadPageView tabPanel            =   null;

			// Tabs are inserted dynamically in the TabStrip
			RadTab tabDefault               =   null;
			HtmlGenericControl _fieldset    =   null;
			// this table will contain the setting items for this pageview
			Table _tbl                      =   null;

			// Seetings items are ordered by group in the collection SettingsOrder
			// so we go through the collection and for each new group, we add a RadTab and a PagView, settings items will be added in the RadPageView
			// until we change group
			SettingItemGroup currentGroup   = SettingItemGroup.NONE;
			foreach (string currentSetting in SettingsOrder.Values)
			{
				SettingItem currentItem     = DataSource[currentSetting];
				if ( currentItem.Group != currentGroup )
				{
					// storing previously built tabpanel
					if (_fieldset != null ) // add built fieldset
					{
						tabStrip.Tabs.Add(tabDefault);
						_fieldset.Controls.Add(_tbl);
						tabPanel.Controls.Add(_fieldset);
						RMP.PageViews.Add(tabPanel);
						if ( SettingsTableTrace.Sw.TraceVerbose )
							Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable createGroupingTabs currentItem.Group:{0}", currentItem.Group),SettingsTableTrace.Sw.Info);
					}
					// start a new fieldset
					_fieldset               =   CreateNewFieldSet(currentItem);
					if ( MPHeight.Value != 0 )
						_fieldset.Style.Add(HtmlTextWriterStyle.Height,"100%");
					// new Tab
					tabDefault              =   new RadTab();
					tabDefault.Text         =   currentItem.ExGroupDescription;
					//tabDefault.ID           =   string.Format("Rdtb_{0}", currentSetting);
					//tabDefault.ClientIDMode =   System.Web.UI.ClientIDMode.Static;
					// new content
					tabPanel                =   new RadPageView();
					tabPanel.ID             =   string.Format("PgV_{0}",currentSetting);
					tabPanel.ClientIDMode   =   System.Web.UI.ClientIDMode.Static;
					if ( !IsVertical )
						tabPanel.Width      =   new Unit("100%");
					if ( !MPHeight.IsEmpty && (MPHeight.Value != 0 ))
						tabPanel.Height     =   MPHeight;

					// start a new table
					_tbl                =   new Table();
					_tbl.CellPadding    =   CellPadding;
					_tbl.CellSpacing    =   CellSpacing;
					_tbl.CssClass       =   "SettingsTableGroup";
					_tbl.Style.Add(HtmlTextWriterStyle.Width, "100%");
					_tbl.Style.Add("table-layout", "fixed"); // Telerik Bug 2009.2.311
					currentGroup        =   currentItem.Group;
				}
				bool Ok                 =   CreateOneSettingRow(currentSetting, currentItem, _tbl);
				if ( SettingsTableTrace.Sw.TraceVerbose )
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateGroupingTabs currentSetting: {0}, Ok: {1}", currentSetting,Ok),SettingsTableTrace.Sw.Info);
			}

			// datas for last group
			tabStrip.Tabs.Add(tabDefault);
			_fieldset.Controls.Add(_tbl);
			tabPanel.Controls.Add(_fieldset);
			RMP.PageViews.Add(tabPanel);

			tabPanelGroup.Controls.Add(tb0);
			base.Controls.Add(tabPanelGroup);
		   
			if ( saveinViewState )
				ViewState[strCtrlCount]  =   SettingsOrder.Count;
			if (SettingsTableTrace.Sw.TraceVerbose)
				Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture, "[V]SettingsTable CreateGroupingTabs END saveinViewState: {0}, SettingsOrder.Count: {1}.",
					saveinViewState, SettingsOrder.Count), SettingsTableTrace.Sw.Info);
		}

		/// <summary>
		/// Returns a new field set with legend for a new settings group
		/// </summary>
		/// <param name="currentItem">
		/// The settings item
		/// </param>
		/// <returns>
		/// Fieldset control
		/// </returns>
		private HtmlGenericControl CreateNewFieldSet(SettingItem currentItem)
		{
			// start a new fieldset
			HtmlGenericControl fieldset     = (UseFieldSet) ? new HtmlGenericControl(StStr.Fieldset): new HtmlGenericControl(StStr.Div);
			fieldset.Attributes.Add("class", "SettingsTableFieldSet");
			fieldset.ID                     =   string.Format("fieldSt_{0}",currentItem.Key);
			fieldset.ClientIDMode           =   System.Web.UI.ClientIDMode.Static;
			// create group legend
			if ( UseFieldSet && UseLegend )
			{
				HtmlGenericControl legend   =   new HtmlGenericControl("legend");
				legend.ID                   =   string.Format("Legd_{0}",currentItem.Key);
				legend.ClientIDMode         =   System.Web.UI.ClientIDMode.Static;
				legend.Attributes.Add("class", "SettingsTableLegend");
				Label legendText            =   new Label();
				legendText.ID               =   string.Format("LegdTxt_{0}",currentItem.Key);
				legendText.ClientIDMode     =   System.Web.UI.ClientIDMode.Static;
				legendText.Text             =   currentItem.ExGroupDescription;
				legendText.CssClass         =   "SettingsTableLegendText";
				legend.Controls.Add(legendText);
				fieldset.Controls.Add(legend);
			}
			return fieldset;
		}

		/// <summary>
		/// Returns one settings row that contains a cell for help, a cell for setting item
		/// name and a cell for setting item and validators.
		/// </summary>
		private bool CreateOneSettingRow(string currentSetting,SettingItem currentItem,Table _tbl)
		{
			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateOneSettingRow BEG currentSetting: {0}, currentItem.key: {1}",currentSetting,currentItem.Key),SettingsTableTrace.Sw.Info);

			// the table row is going to have three cells 
			TableRow row			    =	new TableRow();
			row.CssClass                =   "SettingsTableRow";
					
			// cell for help icon and description
			TableCell helpCell		    =	new TableCell();
			Image img				    =	new Image();
			img.ID                      =   "hlpbtn_"+currentSetting;
			img.ClientIDMode            =   System.Web.UI.ClientIDMode.Static;
			img.SkinID				    =	"Buttons_Help";
			string lstr				    =	currentItem.ExDescription;
			string ctrlTxt			    =	currentItem.ExName;
			bool hasHelpTxt             =   !string.IsNullOrEmpty(lstr);
			if ( hasHelpTxt )
			{
				img.AlternateText	    =	lstr;
				img.ToolTip             =	lstr;
				// Tooltips 
				if ( UseToolTips )
					TarGetToolTips.Add(img);
				if ( SettingsTableTrace.Sw.TraceVerbose )
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateOneSettingRow currentSetting: {0}, Description: {1}", currentSetting,lstr),SettingsTableTrace.Sw.Info);
			}
			else
			{
				img.SkinID			    =	"Spacer";
				img.Width			    =	Unit.Pixel(25);
			}

			helpCell.Controls.Add(img);
			helpCell.Width              =   new Unit("5%");
			helpCell.CssClass           =   "SettingsTableHelpCell";

			// add help cell to the row
			row.Cells.Add(helpCell);

			// Setting Name cell
			TableCell nameCell		    =	new TableCell();
			nameCell.Width              =   new Unit("25%");
			nameCell.CssClass           =   "SettingsTableLabelCell";
			Literal nameText		    =	new Literal();
			nameText.Text			    =	ctrlTxt;
			nameCell.Controls.Add(nameText);

			// add name cell to the row
			row.Cells.Add(nameCell);

			// Setting Control cell
			TableCell settingCell       =	new TableCell();
			settingCell.Width           =   new Unit("65%");
			settingCell.CssClass        =   "SettingsTableCell";
			// When fullWidth, create a second row with all width
			if (currentItem.FullWidth)
			{
				row.Cells.Add(settingCell);
				_tbl.Rows.Add(row);
				row			            =	new TableRow();
				row.CssClass            =   "SettingsTableRow";
				settingCell             =	new TableCell();
				settingCell.ColumnSpan  =   3;
				settingCell.Width       =   new Unit("100%");
				settingCell.CssClass    =   "SettingsTableCell";
			}

			Control editControl         =   null;
			bool Ok                     =   false;
			try
			{
				editControl                 =   currentItem.EditControl;
				editControl.ID              =   currentSetting;
				editControl.ClientIDMode    =   System.Web.UI.ClientIDMode.Static;
				if ( SettingsTableTrace.Sw.TraceVerbose )
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateOneSettingRow  editControl: {0}, ID: {1}, EnableViewState: {2}", editControl,editControl.ID,editControl.EnableViewState),SettingsTableTrace.Sw.Info);
				if (!editControl.EnableViewState && (editControl is RadTreeComboPages) || (editControl is SelListBox))
					editControl.EnableViewState =   true;
				else editControl.EnableViewState =   false;
				Ok                          =   true;
			}
			catch (Exception ex)
			{
				if ( SettingsTableTrace.Sw.TraceError )
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SettingsTable CreateOneSettingRow EditControl for: ['{0}'], ex : {1}", currentItem.EnglishName, ex),SettingsTableTrace.Sw.Info);
				// mark it as bad for editing
				currentItem.StatusOk        =   false;
				//throw;
			}
			if ( Ok )
			{
				SettingsTableItemEventArgs e    =   new SettingsTableItemEventArgs(currentItem,TableType);
				// Just before inserting we inform of creation
				OnItemCreated(e);

				settingCell.Controls.Add(editControl);
				// Telerik RadTextBox bug in 2009.1.311
				if ( ( currentItem.DataType is StringDataType ) &&
						(currentItem.DataType.controlWidth.Type == UnitType.Percentage) &&
						(currentItem.DataType.controlWidth.Value == 100.0 ) )
					currentItem.DataType.controlWidth   =   new Unit("98%");
				//Add control to edit controls collection
				EditControls.Add(currentSetting, editControl);

				/// Validators
				// checkbox can't be validated 
				if ( SettingsTableTrace.Sw.TraceError && currentItem.Required && !currentItem.Ok4Validators )
				{
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SettingsTable Setting is boolean and can't be a required fied : {0}", currentSetting),SettingsTableTrace.Sw.Info);
				}
				bool validatorAdded                 =   false;
				//Required
				if ( currentItem.Required && currentItem.Ok4Validators && !currentItem.SelfRequiredValidator ) 
				{
					RequiredFieldValidator req      =	new RequiredFieldValidator();
					req.ErrorMessage                =	LocalizeHelper.Localize("SETTING_REQUIRED", "%1% is required!").Replace("%1%", currentSetting);
					req.Text						=	"*";
					req.ControlToValidate           =	currentSetting;
					req.ID							=	currentSetting.Trim() + "_req_validator";
					req.CssClass                    =	"Error";
					req.Display                     =	ValidatorDisplay.Dynamic;
					//req.EnableClientScript          =	( UseAjax) ? false:true;
					if ( SettingsTableTrace.Sw.TraceVerbose )
						Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateOneSettingRow Adding required validator to : {0}",currentSetting),SettingsTableTrace.Sw.Info);
					settingCell.Controls.Add(new LiteralControl("<br />"));
					settingCell.Controls.Add(req);
					validatorAdded                  =   true;
				}

				//Range Validator: necessary if seting don't assumes it directly
				if ( !currentItem.SelfRangeValidator && (currentItem.MinValue != 0 || currentItem.MaxValue != 0))
				{
					RangeValidator rang             =   new RangeValidator();

					switch (currentItem.DataTypeType)
					{
						case PropertiesDataType.String:
							rang.Type               =   ValidationDataType.String;
							break;

						case PropertiesDataType.Integer:
							rang.Type               =   ValidationDataType.Integer;
							break;

						case PropertiesDataType.Currency:
							rang.Type               =   ValidationDataType.Currency;
							break;

						case PropertiesDataType.Date:
							rang.Type               =   ValidationDataType.Date;
							break;

						case PropertiesDataType.Double:
							rang.Type               =   ValidationDataType.Double;
							break;
					}

					if ( SettingsTableTrace.Sw.TraceVerbose )
						Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateOneSettingRow Adding Range validator type: {0}",rang.Type),SettingsTableTrace.Sw.Info);
					if ( currentItem.MinValue != 0 && ( (currentItem.MaxValue == 0) || ( currentItem.MaxValue >= currentItem.MinValue )) )
					{
						rang.MinimumValue           =   currentItem.MinValue.ToString();

						if (currentItem.MaxValue == 0)
						{
							rang.ErrorMessage       =   LocalizeHelper.Localize("SETTING_EQUAL_OR_GREATER", "%1% must be equal or greater than %2%!").Replace("%1%", currentSetting).Replace("%2%", currentItem.MinValue.ToString());
						}
						else
						{
							rang.MaximumValue       =   currentItem.MaxValue.ToString();
							rang.ErrorMessage       =   LocalizeHelper.Localize("SETTING_BETWEEN", "%1% must be between %2% and %3%!").Replace("%1%", currentSetting).Replace("%2%", currentItem.MinValue.ToString()).Replace("%3%", currentItem.MaxValue.ToString());
						}
						rang.ControlToValidate          =   currentSetting;
						rang.CssClass                   =   "Error";
						rang.Display                    =   ValidatorDisplay.Dynamic; 
						//rang.EnableClientScript         =   ( UseAjax) ? false:true;
						if ( !validatorAdded )
							settingCell.Controls.Add(new LiteralControl("<br />"));
						settingCell.Controls.Add(rang);
						validatorAdded                  =   true;
					}
				}
			}
			// add setting cell into the row
			row.Cells.Add(settingCell);

			if ( SettingsTableTrace.Sw.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SettingsTable CreateOneSettingRow END currentSetting: {0}",currentSetting),SettingsTableTrace.Sw.Info);
		   // all done send it back
		   _tbl.Rows.Add(row);
		   return Ok;
		}

		#endregion
	}
	#endregion
}